/*************************************************************************************************************
*                                                    UTOS
*                               A non-preemptive(cooperative) multitasking RTOS Kernel
*
* Copyright (c) 2013, HuangLiang (huangliang.tj@gmail.com)
* Under New BSD license, see "LICENSE" for detail
*
* @.file       utos.h
* @.version    refer to macro "UT_VERSION" in utos.h
* @.brief      
*          * Double level scheduling:
*               Level 1, Thread.
*                   The callback function of a thread is the real "task" of this system, all the works you designed
*                   to do is in the callback function. The role of UTOS (and other RTOS, basically)is actually
*                   deciding which callback function to call at a specified time. The criterion for this decision
*                   is the state of each thread and its priority. If a thread is ready, so system will call its
*                   callback function. If more than one thread is ready at the same time, system will run the
*                   thread of higher prio. There are 2 ways to set ready of a thread.
*                   #1, by time tick. Every thread has a time counter, name "timeout", which will decrease for
*                   each system tick. When timeout reaches zero, this thread is set to ready and the system
*                   scheduler will run this thread if possible.
*                   #2, by event. There are several type of event in UTOS, e.g. semaphore. If a semaphore is
*                   posted any where in the program, it will set ready of a related thread, so that thread will
*                   be scheduled to run just like 

*               Level 2, Process.
*                   Each process has an unique priority, using hash table to schedule, so it has a fixed time
*                   for scheduling. A process is like a container to hold a multiple number of thread. 
*              1.To Find Priority:
*                   for PROCESS (UT_PCB), it will use a "hash-table" to find the highest priority one.
*                   for THREAD (UT_TCB), it will use "priority queue" to find the highest priority one
*              2."prio" meaning (field in UT_TCB and UT_PCB): 
*                   for PROCESS, two process can not have the same prio, if you try to create a process
*                 with a prio just used, it will not be created successfully.
*                   but for THREAD, while it's not recommend to have two threads with the same prio, you can 
*                 actually create two (or more) threads with the same prio. Therefor, prio will loss its original
*                 meaning, the true "priority" of these threads depends on when was it created. The last created
*                 one has a higher "priority".
*              3. How many threads can a process have?
*                    A process can actually keeps a infinite number of threads(of course no bigger than UT_THREAD_MAX
*                 in utos_cfg.h). When you use UT_Thread_Create() to attach a thread to a process, it will not
*                 check the max number a process can have. But don't be confused with "tpq_size" in UT_PCB.
*                 this field means the max number you can push into the priority queue of threads. That is to say,
*                 you can attach as many threads to a process as you like, but the number of threads that can be
*                 push into the priority queue is limited, which may lead to some "dead" threads that may not
*                 be run at all. But that also depends on your design.
*************************************************************************************************************/

#ifndef  __UTOS_H
#define  __UTOS_H

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef   UT_GLOBAL
#define  UT_EXT
#else
#define  UT_EXT    extern
#endif

#include "utos_cfg.h"
#include "utos_port.h"


#define  UT_VER_MAJOR                      0x0u             // major ver
#define  UT_VER_MINOR                     0x01u             // minor ver
#define  UT_VER_BUILD                     0x02u             // build ver

/* Version Number forms like [major.minor.build], stored in hex number 0x---ABBCC
* where A-major, BB-minor, CC-build. Top 12 bits is meaningless
*/
#define  UT_VERSION                      ( (UT_VER_MAJOR<<16) | (UT_VER_MINOR<<8)|UT_VER_BUILD|0x14B00000 )

#define  UT_VER_GET_MAJOR                ( (UT_VERSION & 0x000f0000)>>16 )
#define  UT_VER_GET_MINOR                ( (UT_VERSION & 0x0000ff00)>>8 )
#define  UT_VER_GET_BUILD                ( (UT_VERSION & 0x000000ff) )



#if UT_PROCESS_LOWEST_PRIO <= 63
#define  UT_PCB_Tbl_Size         ((UT_PROCESS_LOWEST_PRIO) / 8 + 1)   /* Size of process ready table   */
#else
#define  UT_PCB_Tbl_Size         ((UT_PROCESS_LOWEST_PRIO) / 16 + 1)  /* Size of process ready table   */
#endif

#define  UT_EVENT_MAX            (UT_SEM_MAX + UT_MUTEX_MAX)



/*************************************************************************************************************
*                                               Utility defines
*************************************************************************************************************/
#define  UT_DISABLED                                      0
#define  UT_ENABLED                                       1

#define  UT_FALSE                                         0
#define  UT_TRUE                                          1

#define  UT_NO                                            0
#define  UT_YES                                           1

#define  UT_OFF                                           0
#define  UT_ON                                            1

#define  UT_CLR                                           0
#define  UT_SET                                           1

#define  UT_ACTIVE                                        0
#define  UT_INACTIVE                                      1

#define  UT_FAIL                                          0
#define  UT_OK                                            1


/*************************************************************************************************************
*                                               Error returns
*************************************************************************************************************/
#define  UT_ERR_NONE                           0u   // No error, return success
#define  UT_ERR_SYS_NOT_RUNNING                1u   // System is still initializing
#define  UT_ERR_PNULL                          2u   // The input argument has a NULL pointer
#define  UT_ERR_P_FUNC_NULL                    3u   // The function pointer is null
#define  UT_ERR_PROC_PRIO_INVALID              4u   // Process priority is not a valid number
#define  UT_ERR_PROC_FULL                      5u   // Process pool is full, can not create new process
#define  UT_ERR_PROC_HEAP_NULL                 6u   // Process has a Null thread heap
#define  UT_ERR_PROC_ZERO_THREAD               7u   // Each process must have at least 2 threads
#define  UT_ERR_PROC_PRIO_USED                 8u   // The specified priority has been assigned before
#define  UT_ERR_PROC_PRIO_NOT_EXIST            9u   // The priority specified does not exist.
#define  UT_ERR_PROC_MUTED                    10u   // The process is muted
#define  UT_ERR_PROC_PQ_NOT_DYN               11u   // The process does not have a dynamic pq, can't add thread 
#define  UT_ERR_PROC_NAME_NONE                12u   // The process's name can not be set to a none pointer
#define  UT_ERR_THRD_PRIO_INVALID             13u   // Thread priority is not a valid number
#define  UT_ERR_THRD_FULL                     14u   // Thread pool is full
#define  UT_ERR_THRD_EMPTY                    15u   // Thread pool is empty
#define  UT_ERR_THRD_PRIO_NOT_EXIST           16u   // The priority specified does not exist.
#define  UT_ERR_THRD_ASLEEP                   17u   // The thread is asleep, can not be set ready
#define  UT_ERR_EVT_NOT_CREATE                18u   // The specified UT_EVENT has not been created yet
#define  UT_ERR_EVT_MUTED                     19u   // The event is muted, can not be triggered
#define  UT_ERR_SEM_NOT_CREATE                20u   // The sem has not been created


#define  UT_PRIO_KER_PROC                    0x0u   // Reserved for kernel process priority, highest prio
#define  UT_PRIO_PROC_SELF                  0xffu   // Reserved for priority indicating self
#define  UT_PRIO_THRD_SELF                  0xffu   // Reserved for priority indicating self

/*************************************************************************************************************
*                                           Thread control block status   (UT_TCB/stat)
*************************************************************************************************************/
#define  UT_TCB_STAT_TIMEOUT                0x00u   // Thread is waiting for timeout, its the most normal state
#define  UT_TCB_STAT_READY                  0x01u   // Thread has been put input ready prio-queue
#define  UT_TCB_STAT_SLEEP                  0x02u   // Thread is sleeping, can not be triggered by any means
#define  UT_TCB_STAT_EVT_PEND               0x04u   // Thread is pending for an event
//#define  UT_TCB_STAT_FLAG                   0x04u    // Thread is waiting for flag
//#define  UT_TCB_STAT_SEM                    0x08u    // Thread is pending for semaphore
//#define  UT_TCB_STAT_MBOX                   0x10u    // Thread is pending for message box
//#define  UT_TCB_STAT_Q                      0x20u    // Thread is pending for queue
//
//#define  UT_TCB_STAT_PEND_ANY               ( UT_TCB_STAT_SEM | UT_TCB_STAT_MBOX | UT_TCB_STAT_Q )

/*************************************************************************************************************
*                                           Process control block status   (UT_PCB/stat)
*************************************************************************************************************/
#define  UT_PCB_STAT_READY_ANY              0x00u     // At least one thread of this process is ready
#define  UT_PCB_STAT_PEND                   0x01u     // All thread of this process is pending
#define  UT_PCB_STAT_MUTE                   0x02u     // Process is muted, all threads of this process is suspended
//#define  UT_PCB_STAT_SOLO                   0x04u     // Process is set to solo list

#define  UT_PCB_OPT_NONE                    0x00u     // Process has a no options
#define  UT_PCB_OPT_DYN_PQ                  0x01u     // Process has a dynamic pq, can hold more thread than pq'size 

#define  UT_EVT_TYPE_INIT                   0x00u     // Initial, linked list
#define  UT_EVT_TYPE_SEM                    0x01u     // Event type: semaphore
#define  UT_EVT_TYPE_MUTEX                  0x02u     // Event type: mutex

#define  UT_EVT_OPT_COST                    0x00u
#define  UT_EVT_OPT_NOT_COST                0x01u

/*************************************************************************************************************
*                                             Type defines
*************************************************************************************************************/
/* type: Thread control block */
typedef struct _UT_TCB{
    struct _UT_TCB       *p_prev;                          // Pointer to previous UT_TCB type
    struct _UT_TCB       *p_next;                          // Pointer to next UT_TCB type
    
    struct _UT_PCB       *p_pcb;                           // Pointer to the PCB attached to 
    struct _UT_EVENT     *p_event;                         // Pointer to a event
    
    UT_INT32U             timeout;                         // Timeout counter, 0 means forever
    UT_INT32U             timeout_reg;                     // Timeout counter register
    void               *(*thread_callback)(void* p_arg);   // Thread callback function
    void                 *p_thread_arg;                    // Argument of thread callback function
    void                 *p_thread_rtn;                    // Return value of thread callback function
    
    UT_INT8U              prio;                            // Thread priority, 0-255
    UT_INT8U              stat;                            // Thread status, refer to UT_TCB_STAT_xxx macro
    
}UT_TCB;

/* type: Process control block */
typedef struct _UT_PCB{
    struct _UT_PCB       *p_prev;                          // Pointer to previous UT_PCB type
    struct _UT_PCB       *p_next;                          // Pointer to next UT_PCB type
    
    struct _UT_TCB       *p_tcb_list;                      // Pointer to TCB list (tail) attached to this process
    UT_INT32U             tcb_cnt;                         // Number of TCBs currently attached to this process
    
    void                **tpq;                             // Thread priority queue base pointer, used for thread schedular
    UT_INT32U             tpq_entry;                       // Thread priority queue free entry. 0 will never be used
    UT_INT32U             tpq_size;                        // Thread priority queue total size.

    UT_INT8U              rdy_grp;                         // Process ready group number, pre-calcu to speed up
    UT_INT8U              rdy_tbl;                         // Process ready table number, pre-calcu to speed up
#if UT_PROCESS_LOWEST_PRIO <= 63
    UT_INT8U              rdy_grp_bit;                     // Process ready group bit access, pre-calcu to speed up
    UT_INT8U              rdy_tbl_bit;                     // Process ready table bit access, pre-calcu to speed up
#else
    UT_INT16U             rdy_grp_bit;                     // Process ready group bit access, pre-calcu to speed up
    UT_INT16U             rdy_tbl_bit;                     // Process ready table bit access, pre-calcu to speed up
#endif
    
    UT_INT8U              prio;                            // Process priority, 0-255
    UT_INT8U              stat;                            // Process status
    UT_INT8U              opt;                             // Process options, see macro 
#if  UT_PROCESS_NAME_EN > 0
    UT_INT8S             *p_pcb_name;                      // PCB name, point to a string in flash or RAM
#endif
}UT_PCB;

/* type: Event */
typedef struct _UT_EVENT{
    void                 *ptr;                             // As linked list, static, point to other trigger when dynamic
    struct _UT_TCB       *p_thread;                        // Pointer to thread. thread and event have a "one to one"

    UT_INT8U              event_type;                      // UT_EVT_TYPE_XX
    UT_INT8U              event_opt;                       // UT_EVT_OPT_XX
}UT_EVENT;


typedef struct _UT_SEM{
    void                *ptr;                              // As linked list when static, point to a event when dynamic
}UT_SEM;

typedef struct _UT_MUTEX{
    void                *ptr;                              // As linked list when static, point to a event when dynamic
    UT_INT8U             thrd_pip;                         // Priority inheritance priority
    UT_INT8U             proc_pip;
}UT_MUTEX;


/*************************************************************************************************************
*                                            Global Variables
*************************************************************************************************************/
#if UT_PROCESS_LOWEST_PRIO <= 63
UT_EXT  UT_INT8U            UT_PCB_Rdy_Grp;
UT_EXT  UT_INT8U            UT_PCB_Rdy_Tbl[UT_PCB_Tbl_Size];
#else
UT_EXT  UT_INT16U           UT_PCB_Rdy_Grp;
UT_EXT  UT_INT16U           UT_PCB_Rdy_Tbl[UT_PCB_Tbl_Size];
#endif


UT_EXT  UT_PCB              UT_PCB_Pool[UT_PROCESS_MAX];
UT_EXT  UT_INT32U           UT_PCB_Created_Num;
UT_EXT  UT_PCB             *UT_PCB_Free_Entry;                               //current free entry of UT_PCB_Pool[]
UT_EXT  UT_PCB             *UT_PCB_Prio_Tbl[UT_PROCESS_LOWEST_PRIO+1];
UT_EXT  UT_PCB             *UT_PCB_List;
UT_EXT  UT_PCB             *UT_PCB_Runtime_Cur;            // Always point to current PCB in runtime (UT_PRIO_PROC_SELF)

UT_EXT  UT_TCB              UT_TCB_Pool[UT_THREAD_MAX];
UT_EXT  UT_INT32U           UT_TCB_Created_Num;
UT_EXT  UT_TCB             *UT_TCB_Free_Entry;
UT_EXT  UT_TCB             *UT_TCB_Runtime_Cur;            // Always point to current TCB in runtime (UT_PRIO_THRD_SELF)

UT_EXT  UT_EVENT            UT_EVENT_Pool[UT_EVENT_MAX];
UT_EXT  UT_INT32U           UT_EVENT_Created_Num;
UT_EXT  UT_EVENT           *UT_EVENT_Free_Entry;


UT_EXT  UT_SEM              UT_SEM_Pool[UT_SEM_MAX];
UT_EXT  UT_INT32U           UT_SEM_Created_Num;
UT_EXT  UT_SEM             *UT_SEM_Free_Entry;


/*************************************************************************************************************
*                                             Function prototypes
*************************************************************************************************************/

/* utos_core.c */
void          UT_Init                       (void);
void          UT_Main                       (void);
void          UT_Tick                       (void);
UT_INT8U      UT_Core_Set_HighRdy           (UT_PCB *p_proc, UT_TCB   *p_thrd);


/* utos_process.c */
void          UT_Process_Init               (void);
UT_INT8U      UT_Process_Create             (UT_INT8U prio,  void ** thread_heap,  UT_INT32U thread_capacity);
UT_INT8U      UT_Process_Create_Ext         (UT_INT8U prio, void ** thread_pq_heap, UT_INT32U thread_pq_size,
                                                UT_INT8S *pcb_name, UT_INT8U pcb_opt);
UT_INT8U      UT_Process_Delete             (UT_INT8U prio);
UT_PCB      * UT_Process_Find_Proc_Prio     (UT_INT8U prio);

/* utos_thread.c */
void          UT_Thread_Init                (void);
UT_INT8U      UT_Thread_Create              (UT_INT8U proc_prio, UT_INT8U thrd_prio, 
                                                void* (*thrd_cb_func)(void*), UT_INT32U thrd_timeout, void * thrd_arg);
UT_INT8U      UT_Thread_Delete              (UT_INT8U proc_prio, UT_INT8U thrd_prio);
UT_INT8U      UT_Thread_Delete_Self         (void);
UT_TCB      * UT_Thread_Find_Thrd_Prio      (UT_INT8U proc_prio, UT_INT8U thrd_prio);
UT_INT8U      UT_Thread_Arg_Set             (UT_INT8U proc_prio, UT_INT8U thrd_prio, void * thrd_arg);
UT_TCB      * UT_Thread_Fork                (UT_INT8U *err);
UT_TCB      * UT_Thread_Fork_2              (UT_INT8U *err, void* (*thrd_cb_func)(void*));
UT_TCB      * UT_Thread_Fork_3              (UT_INT8U *err, void* (*thrd_cb_func)(void*), UT_INT32U thrd_timeout);

/* utos_event.c */
void          UT_Evt_Init                   (void);
UT_EVENT    * UT_Evt_Create                 (UT_TCB   *p_thrd);
UT_INT8U      UT_Evt_Delete                 (UT_EVENT *p_event);
UT_INT8U      UT_Evt_Mute                   (UT_EVENT *p_event);
UT_INT8U      UT_Evt_Active                 (UT_EVENT *p_event);
UT_INT8U      UT_Evt_Signal                 (UT_EVENT *p_event);
UT_INT8U      UT_Evt_Set_Opt                (UT_EVENT *p_event, UT_INT8U evt_opt);

/* utos_sem.c */
void          UT_Sem_Init                   (void);
UT_SEM      * UT_Sem_Create                 (UT_TCB *p_thrd);
UT_SEM      * UT_Sem_Create_Prio            (UT_INT8U proc_prio, UT_INT8U thrd_prio);
UT_INT8U      UT_Sem_Delete                 (UT_SEM *p_sem);
UT_INT8U      UT_Sem_Post                   (UT_SEM *p_sem);

/* utos_mem.c */
void          UT_MemCpy                     (void  *pdest, const void *psrc, UT_INT32U size);
void          UT_MemSet                     (void  *pdest, UT_INT32U size);
void          UT_MemClr                     (void  *pdest, UT_INT32U size);
UT_BOOLEAN    UT_MemCmp                     (void const *pmem1,  void const *pmem2, UT_INT32U size);

#ifdef  __cplusplus
}
#endif
#endif      /* #ifndef  __UTOS_H */
/*************************************************************************************************************
*                                                  END
*************************************************************************************************************/
